#pragma once
#include <brpc/closure_guard.h>
#include <memory>
#include <brpc/server.h>
#include <odb/database.hxx>
#include <odb/mysql/database.hxx>

#include "etcd.hpp"
#include "etcd_path.h"
#include "home.pb.h"
#include "es.h"
// #include "brpc.h"
// #include "mysql.h"
// #include "redis.h"



namespace lyt{
    class HomeServiceImpl : public home::HomeService{
    private:
        // es
        esclient::ptr _esclient;
        index::ptr _index;
        search::ptr _search;
    public:
        using ptr = std::shared_ptr<HomeServiceImpl>;
        HomeServiceImpl(esclient::ptr esclient):
                        _esclient(esclient),
                        _index(std::make_shared<index>(esclient)),
                        _search(std::make_shared<search>(esclient)){}
        void GetHomeData(){
            
        }
        void Search(google::protobuf::RpcController* controller,
                       const home::SearchRequest* request,
                       home::SearchResponse* response,
                       google::protobuf::Closure* done){
            brpc::ClosureGuard doneguard(done);
            auto handler = [&](const bool success,const std::string& message=""){
                response->set_success(success);
                response->set_message(message);
                return;
            };
        }
    };
    class HomeServer{
    private:
        HomeServiceImpl::ptr _home;
        lyt::Register::ptr _register;
        std::shared_ptr<brpc::Server> _server;
    public:
        using ptr = std::shared_ptr<HomeServer>;
        HomeServer(const std::shared_ptr<brpc::Server>& svr
                  ,const HomeServiceImpl::ptr& home
                  ,const lyt::Register::ptr& regis):
                  _server(svr),_register(regis),_home(home){}
        void start(){
            _server->RunUntilAskedToQuit();
        }
    };
    class HomeServerBuild{
    private:
        // odb redis 可能不需要,之后酌情删减
        // std::shared_ptr<odb::mysql::database> _odb;
        // std::shared_ptr<sw::redis::Redis> _redis;
        HomeServiceImpl::ptr _home;
        lyt::Register::ptr _register;
        std::shared_ptr<brpc::Server> _server;
        esclient::ptr _esclient;
    public:
        using ptr = std::shared_ptr<HomeServerBuild>;
        // HomeServerBuild& make_odb_client(
        //         const std::string& user,
        //         const std::string& passwd,
        //         const std::string& db_name,
        //         const std::string& host,
        //         size_t port,
        //         const std::string& charset,
        //         size_t conn_pool_num){
        //             _odb = lyt::mysql_build::build(user, passwd, db_name, host, port, charset, conn_pool_num);
        //             return *this;
        // }
        // HomeServerBuild& make_redis_client(const std::string& host,int port, int db_id,bool keepalive = true) {
        //     _redis = redis_build::build(host, port, db_id,keepalive);
        //     return *this;
        // }
        HomeServerBuild& make_elasticsearch_client(const std::vector<std::string>& host){
            _esclient = std::make_shared<esclient>(host);
            return *this;
        }
        HomeServerBuild& make_home_service() {
            // if (!_odb) {
            //     errorlog << "failed to odb uninitizalier";
            //     abort();
            // }
            // if (!_redis) {
            //     errorlog << "failed to redis uninitizalier";
            //     abort();
            // }
            if(!_esclient){
                errorlog << "failed to esclient uninitizalier";
                abort();
            }
            _home = std::make_shared<HomeServiceImpl>(_esclient);
            return *this;
        }

        HomeServerBuild& make_brpc_server(const std::size_t& port) {
            if(!_home){
                errorlog << "UserService uninitizalier";
                abort();
            }
            _server = std::make_shared<brpc::Server>();
            if(_server->AddService(&(*_home),brpc::SERVER_DOESNT_OWN_SERVICE) != 0){
                errorlog << "Failed to add service: UserService";
                abort();
            }
            brpc::ServerOptions options;
            options.idle_timeout_sec = -1;
            if(_server->Start(port,&options) != 0){
                errorlog << "Failed to start service: UserService";
                abort();
            }
            return *this;
        }
        HomeServerBuild& make_register(const std::string& host,const std::string& value) {
            if(!_server){
                errorlog << "Can't register to etcd,because UserService not start";
                abort();
            }
            _register = std::make_shared<lyt::Register>(host);
            if(!_register->registory(lyt::home_path + value, value)){
                errorlog << "Fail register UserService to etcd";
                abort();
            }
            return *this;
        }

        HomeServer::ptr build() {
            if (!_server) {
                errorlog << "failed to brpc uninitizalier";
                abort();
            }
            if (!_home) {
                errorlog << "failed to user uninitizalier";
                abort();
            }
            if (!_register) {
                errorlog << "failed to register uninitizalier";
                abort();
            }
            return std::shared_ptr<HomeServer>(new HomeServer(_server,_home,_register));
        }
    };
}